Discriminated records are implemented without hidden pointers: if the position of a record component depends on a discriminant (for example if the size of a previous component depends of a discriminant) then GCC generates inline code to compute the address of the component, rather than storing offsets in the object.
the implementation of objects whose size is dynamic makes use of so called fat pointers. A fat pointer is a record with two components: a pointer to an object, and a pointer to a descriptor that contains bounds information on the object. Most accesses to such an object make use of the descriptor. GCC builds fat pointers when needed, for example when passing a composite type in a call to a formal parameter that is an unconstrained type.